﻿namespace SharePointCSVImporter
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Microsoft.SharePoint.Client;

    public class ExternalListLookupWorker : IDisposable
    {
        #region Fields

        static ClientContext thisContext;

        private List<ListItem> externallookupItems;

        #endregion Fields

        #region Properties

        public List<ListItem> ExternallookupItems
        {
            get { return externallookupItems; }
            set { externallookupItems = value; }
        }

        #endregion Properties

        #region Methods

        public void CloseContext()
        {
            if (thisContext != null)
            {
                thisContext.Dispose();
                thisContext = null;
            }
        }

        public void Dispose()
        {
            CloseContext();
        }

        public void GetContext(string url)
        {
            if (thisContext == null)
            {
                thisContext = new ClientContext(url);
            }
            else
            {
                if (!url.Contains(thisContext.Url))
                {
                    thisContext.Dispose();
                    thisContext = new ClientContext(url);
                }

            }
        }

        public void TestListSettings(string webUrl, string listName, string[] fields, Action<bool> callBack)
        {
            if (fields != null && fields.Length > 0 && !string.IsNullOrEmpty(webUrl) && !string.IsNullOrEmpty(listName))
            {
                GetContext(webUrl);
                Web web = thisContext.Web;
                List targetList = web.Lists.GetByTitle(listName);
                FieldCollection listFields = targetList.Fields;
                thisContext.Load(targetList);
                thisContext.Load(listFields);
                thisContext.ExecuteQueryAsync((s, e) =>
                    {
                        if (targetList != null && listFields != null && listFields.Count > 0)
                        {
                            int missingField = 0;
                            foreach (string field in fields)
                            {
                                bool exists = listFields.Any(c => c.InternalName.Equals(field) || c.StaticName.Equals(field));
                                if (!exists)
                                {
                                    missingField++;
                                }
                            }
                            if (missingField > 0)
                            {
                                callBack(false);
                            }
                            else
                            {
                                callBack(true);
                            }
                        }
                        else
                        {
                            callBack(false);
                        }
                    },
                    (s, e) =>
                    {
                        //an error occurred
                        callBack(false);
                    });
            }
            else
            {
                callBack(false);
            }
        }

        internal void GetExternalLookupItems(string webUrl, string listName, Action<List<ListItem>, string> ItemsReceived)
        {
            if (!string.IsNullOrEmpty(webUrl) && !string.IsNullOrEmpty(listName))
            {
                GetContext(webUrl);
                Web web = thisContext.Web;
                List targetList = web.Lists.GetByTitle(listName);
                ListItemCollection listitems = targetList.GetItems(CamlQuery.CreateAllItemsQuery());
                thisContext.Load(targetList);
                thisContext.Load(listitems);
                thisContext.ExecuteQueryAsync((s, e) =>
                {
                    //success
                    externallookupItems = listitems.ToList();
                    ItemsReceived(externallookupItems, "");

                },
                  (s, e) =>
                  {
                      ItemsReceived(null, e.Message);
                  });
            }
            else
            {
                ItemsReceived(null, "You need to provide a web Url and a list name");
            }
        }

        internal void GetFields(string webUrl, string listName, Action<List<Field>, string> FieldsReceived)
        {
            if (!string.IsNullOrEmpty(webUrl) && !string.IsNullOrEmpty(listName))
            {
                GetContext(webUrl);
                Web web = thisContext.Web;
                List targetList = web.Lists.GetByTitle(listName);
                FieldCollection listFields = targetList.Fields;
                thisContext.Load(targetList);
                thisContext.Load(listFields);
                thisContext.ExecuteQueryAsync((s, e) =>
                {
                    //success
                    List<Field> fields = listFields.ToList();
                    fields = fields.Where(c => c.Hidden.Equals(false)).ToList();
                    FieldsReceived(fields, "");

                },
                  (s, e) =>
                  {
                      FieldsReceived(null, e.Message);
                  });
            }
            else
            {
                FieldsReceived(null, "You need to provide a web Url and a list name");
            }
        }

        internal bool ItemExists(Dictionary<string, string> filterFields, string targetField, bool useFirstIfMultiple, bool returnBlankIfNoMatch, string preCheckValue, List<ListItem> itemsToCheck, out string transformedValue)
        {
            bool rvalue = false;
            transformedValue = preCheckValue;
            if (itemsToCheck != null && itemsToCheck.Count > 0 && filterFields != null && filterFields.Count > 0)
            {
               var filters = filterFields.ToList();

                KeyValuePair<string, string> firstFilterField = filters[0];
                IEnumerable<ListItem> possibleMatches = null;

                //  var matchedItems; = possibleMatches.Where(c => c[filter.Key].ToString().ToLower().Trim() != filter.Value.ToLower().Trim());
                if (filterFields.Count.Equals(1) && !string.IsNullOrEmpty(firstFilterField.Key))
                {
                    try
                    {
                        possibleMatches = itemsToCheck.Where(c => c[firstFilterField.Key] !=null && c[firstFilterField.Key].ToString().ToLower().Trim().Equals(firstFilterField.Value.ToLower().Trim()));
                    }
                    catch { possibleMatches = null; }
                    //    matchedItems = possibleMatches.Where(c => c[filter.Key].ToString().ToLower().Trim() != filter.Value.ToLower().Trim());
                }
                else
                {
                    if (filterFields.Count.Equals(2))
                    {
                        KeyValuePair<string, string> secondFilterField = filters[1];
                        try
                        {
                            possibleMatches = itemsToCheck.Where(c => c[firstFilterField.Key] != null && c[secondFilterField.Key] !=null && c[firstFilterField.Key].ToString().ToLower().Trim().Equals(firstFilterField.Value.ToLower().Trim())
                                && c[secondFilterField.Key].ToString().ToLower().Trim().Equals(secondFilterField.Value.ToLower().Trim()));
                        }
                        catch { possibleMatches = null; }
                    }
                    else
                    {
                        if (filterFields.Count.Equals(3))
                        {
                            KeyValuePair<string, string> secondFilterField = filters[1];
                            KeyValuePair<string, string> thirdFilterField = filters[2];
                            try
                            {
                                possibleMatches = itemsToCheck.Where(c => c[firstFilterField.Key] != null && c[secondFilterField.Key] != null && c[thirdFilterField.Key] !=null && c[firstFilterField.Key].ToString().ToLower().Trim().Equals(firstFilterField.Value.ToLower().Trim())
                             && c[secondFilterField.Key].ToString().ToLower().Trim().Equals(secondFilterField.Value.ToLower().Trim()) && c[thirdFilterField.Key].ToString().ToLower().Trim().Equals(thirdFilterField.Value.ToLower().Trim()));
                            }
                            catch { possibleMatches = null; }

                        }
                    }
                }
                if (possibleMatches !=null && possibleMatches.Count() > 0)
                {
                    rvalue = true;
                    if (possibleMatches.Count().Equals(1))
                    {
                        transformedValue = (string)possibleMatches.FirstOrDefault()[targetField];
                    }
                    else
                    {
                        if (useFirstIfMultiple)
                        {
                            transformedValue = (string)possibleMatches.FirstOrDefault()[targetField];
                        }
                    }
                }
                else
                {
                    rvalue = false;
                }

            }

            if (transformedValue.Equals(preCheckValue) && returnBlankIfNoMatch)
            {
                transformedValue = string.Empty;
            }

            return rvalue;
        }

        #endregion Methods
    }
}